package cn.slipi.core.configuration;

import cn.slipi.core.cache.ApiManager;
import cn.slipi.core.filter.LogFilter;
import cn.slipi.core.filter.concrete.ParamRebuildFilter;
import cn.slipi.core.filter.concrete.ParamVerifyFilter;
import cn.slipi.core.handler.CoreWebHandler;
import cn.slipi.core.handler.mapping.CoreWebHandlerMapping;
import cn.slipi.core.plugin.IPlugin;
import cn.slipi.core.plugin.post.ResponsePlugin;
import cn.slipi.core.plugin.pre.*;
import cn.slipi.core.plugin.routing.HttpPlugin;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.server.WebFilter;

import java.util.List;
import java.util.stream.Collectors;

@Configuration
public class CoreConfiguration {

    @Autowired
    private ApiManager apiManager;

    @Bean
    public IPlugin requestPlugin() {
        return new RequestPlugin();
    }

    @Bean
    public IPlugin responsePlugin() {
        return new ResponsePlugin();
    }

    @Bean
    public IPlugin signPlugin() {
        return new SignPlugin(apiManager);
    }

    @Bean
    public IPlugin fireWallPlugin() {
        return new FireWallPlugin(apiManager);
    }

    @Bean
    public IPlugin grayReleasePlugin() {
        return new GrayReleasePlugin(apiManager);
    }

    @Bean
    public IPlugin rateLimiterPlugin() {
        return new RateLimiterPlugin(apiManager);
    }

    @Bean
    public IPlugin httpPlugin() {
        return new HttpPlugin(apiManager);
    }

    @Bean
    public CoreWebHandler coreWebHandler(final List<IPlugin> plugins) {
        List<IPlugin> result = plugins.stream()
                .sorted((m, n) -> {
                    if (StringUtils.equals(m.getPluginPhase(), n.getPluginPhase())) {
                        return m.getCode() - n.getCode();
                    } else {
                        return convertPluginPhaseForCompare(m.getPluginPhase()).compareTo(convertPluginPhaseForCompare(n.getPluginPhase()));
                    }
                }).collect(Collectors.toList());
        return new CoreWebHandler(result);
    }

    @Bean
    public CoreWebHandlerMapping coreWebHandlerMapping(final CoreWebHandler coreWebHandler) {
        return new CoreWebHandlerMapping(coreWebHandler);
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public WebFilter logFilter() {
        return new LogFilter();
    }

    @Bean
    @Order(-1)
    public WebFilter paramRebuildFilter() {
        return new ParamRebuildFilter();
    }

    @Bean
    @Order(1)
    public WebFilter paramVerifyFilter() {
        return new ParamVerifyFilter();
    }

    private String convertPluginPhaseForCompare(String phase) {
        switch (phase) {
            case "pre":
                return "a";
            case "routing":
                return "b";
            case "post":
                return "c";
            default:
                return phase;
        }
    }

}
